package com.biluo.security.config;

import com.biluo.security.custom.CustomMd5PasswordEncoder;
import com.biluo.security.filter.TokenAuthenticationFilter;
import com.biluo.security.filter.TokenLoginFilter;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity //@EnableWebSecurity是开启SpringSecurity的默认行为
@EnableGlobalMethodSecurity(prePostEnabled = true)
@RequiredArgsConstructor
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
	private final StringRedisTemplate stringRedisTemplate;
	private final UserDetailsService userDetailsService;
	private final CustomMd5PasswordEncoder customMd5PasswordEncoder;

	@Bean
	@Override
	protected AuthenticationManager authenticationManager() throws Exception {
		return super.authenticationManager();
	}

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		// 这是配置的关键，决定哪些接口开启防护，哪些接口绕过防护
		http
				// 关闭csrf跨站请求伪造
				.csrf().disable()
				// 开启跨域以便前端调用接口
				.cors().and()
				.authorizeRequests()
				// 指定某些接口不需要通过验证即可访问。登陆接口肯定是不需要认证的
				//.antMatchers("/admin/system/index/login").permitAll()
				// 这里意思是其它所有接口需要认证才能访问
				.anyRequest().authenticated()
				.and()
				// TokenAuthenticationFilter放到UsernamePasswordAuthenticationFilter的前面，这样做就是为了除了登录的时候去查询数据库外，其他时候都用token进行认证。
				.addFilterBefore(new TokenAuthenticationFilter(stringRedisTemplate),
						UsernamePasswordAuthenticationFilter.class)
				.addFilter(new TokenLoginFilter(authenticationManager(), stringRedisTemplate));

		// 禁用session
		http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
	}

	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		// 指定UserDetailService和加密器
		auth.userDetailsService(userDetailsService).passwordEncoder(customMd5PasswordEncoder);
	}

	/**
	 * 配置哪些请求不拦截
	 * 排除swagger相关请求
	 *
	 * @param web
	 * @throws Exception
	 */
	@Override
	public void configure(WebSecurity web) throws Exception {
		web.ignoring().antMatchers("/admin/modeler/**", "/diagram-viewer/**", "/editor-app/**", "/*.html",
				"/admin/processImage/**",
				"/admin/wechat/authorize", "/admin/wechat/userInfo", "/admin/wechat/bindPhone",
				"/favicon.ico", "/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**", "/doc.html");
	}
}
